package com.demandbreakdown.xiyun.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demandbreakdown.xiyun.common.annotation.OperationLog;
import com.demandbreakdown.xiyun.common.base.ResultCode;
import com.demandbreakdown.xiyun.common.exception.BusinessException;
import com.demandbreakdown.xiyun.mapper.PictureMapper;
import com.demandbreakdown.xiyun.mapper.SpaceMapper;
import com.demandbreakdown.xiyun.mapper.SpaceUserMapper;
import com.demandbreakdown.xiyun.mapper.UserMapper;
import com.demandbreakdown.xiyun.model.dto.picture.PictureQueryDTO;
import com.demandbreakdown.xiyun.model.dto.picture.PictureReview;
import com.demandbreakdown.xiyun.model.dto.picture.PictureUpdateDTO;
import com.demandbreakdown.xiyun.model.dto.picture.PictureUploadDTO;
import com.demandbreakdown.xiyun.model.entity.Picture;
import com.demandbreakdown.xiyun.model.entity.Space;
import com.demandbreakdown.xiyun.model.entity.SpaceUser;
import com.demandbreakdown.xiyun.model.entity.User;
import com.demandbreakdown.xiyun.model.enums.ReviewStatusEnum;
import com.demandbreakdown.xiyun.model.enums.SpaceUserRoleEnum;
import com.demandbreakdown.xiyun.model.enums.UserRoleEnum;
import com.demandbreakdown.xiyun.model.vo.common.PageVO;
import com.demandbreakdown.xiyun.model.vo.picture.PictureVO;
import com.demandbreakdown.xiyun.model.vo.user.UserVO;
import com.demandbreakdown.xiyun.service.PictureService;
import com.demandbreakdown.xiyun.service.StorageService;
import com.demandbreakdown.xiyun.service.UserService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.demandbreakdown.xiyun.common.constant.FileConstant.HTTPS_PROTOCOL_PREFIX_LENGTH;
import static com.demandbreakdown.xiyun.common.constant.PictureConstant.*;

/**
 * 图片服务实现类
 *
 * @author poxz
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture>
        implements PictureService {

    // Mapper 层依赖
    private final PictureMapper pictureMapper;
    private final UserMapper userMapper;
    private final SpaceMapper spaceMapper;
    private final SpaceUserMapper spaceUserMapper;

    // Service 层依赖
    private final UserService userService;
    private final StorageService storageService;

    @Override
    @OperationLog("上传图片")
    @Transactional(rollbackFor = Exception.class)
    public PictureVO uploadPicture(Long userId, MultipartFile file, PictureUploadDTO uploadDTO) {
        // 业务验证
        User user = validateUploadPermission(userId, uploadDTO.getSpaceId(), file.getSize());

        // 上传文件
        String fileUrl = storageService.uploadPicture(file, userId, uploadDTO.getSpaceId());
        String filePath = extractFilePath(fileUrl);

        // 提取图片元数据
        Map<String, Object> imageMetadata = extractImageMetadata(file);

        // 创建并保存图片记录
        Picture picture = buildPictureEntity(userId, file, uploadDTO, fileUrl, filePath, imageMetadata);
        boolean saved = this.save(picture);
        if (!saved) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR);
        }

        // 构建返回结果
        PictureVO pictureVO = PictureVO.from(picture);
        pictureVO.setUser(UserVO.from(user));

        return pictureVO;
    }

    /**
     * 验证上传权限和容量
     *
     * @return 用户对象
     */
    private User validateUploadPermission(Long userId, Long spaceId, long fileSize) {
        // 验证用户
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        // 验证空间权限和容量
        if (spaceId != null) {
            validateSpacePermission(userId, spaceId, ACTION_UPLOAD);
            validateSpaceCapacity(spaceId, fileSize);
        }

        return user;
    }

    /**
     * 构建图片实体对象
     */
    private Picture buildPictureEntity(Long userId, MultipartFile file, PictureUploadDTO uploadDTO,
                                       String fileUrl, String filePath, Map<String, Object> imageMetadata) {
        Picture picture = new Picture();

        // 基本信息
        picture.setUserId(userId);
        picture.setSpaceId(uploadDTO.getSpaceId());
        picture.setPictureName(determinePictureName(uploadDTO, file));
        picture.setOriginalName(file.getOriginalFilename());
        picture.setIntroduction(uploadDTO.getIntroduction());
        picture.setCategory(StrUtil.isNotBlank(uploadDTO.getCategory()) ? uploadDTO.getCategory() : CATEGORY_OTHER);

        // 标签
        processTags(picture, uploadDTO.getTags());

        // 文件信息
        picture.setFileUrl(fileUrl);
        picture.setFilePath(filePath);
        picture.setFileSize(file.getSize());
        picture.setPicFormat(FileUtil.extName(file.getOriginalFilename()));

        // 图片尺寸
        setImageDimensions(picture, imageMetadata);

        // 默认值
        picture.setReviewStatus(ReviewStatusEnum.APPROVED.getValue());
        picture.setViewCount(0);
        picture.setDownloadCount(0);
        picture.setShareCount(0);

        return picture;
    }

    /**
     * 确定图片名称
     */
    private String determinePictureName(PictureUploadDTO uploadDTO, MultipartFile file) {
        return StrUtil.isNotBlank(uploadDTO.getPictureName())
                ? uploadDTO.getPictureName()
                : FileUtil.getPrefix(file.getOriginalFilename());
    }

    /**
     * 处理标签
     */
    private void processTags(Picture picture, String tags) {
        if (StrUtil.isBlank(tags)) {
            return;
        }

        List<String> tagList = Arrays.stream(tags.split(","))
                .map(String::trim)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());

        if (!tagList.isEmpty()) {
            picture.setTags(JSONUtil.toJsonStr(tagList));
        }
    }

    /**
     * 设置图片尺寸信息
     */
    private void setImageDimensions(Picture picture, Map<String, Object> imageMetadata) {
        Integer width = (Integer) imageMetadata.get("width");
        Integer height = (Integer) imageMetadata.get("height");
        if (width != null && height != null) {
            picture.setPicWidth(width);
            picture.setPicHeight(height);
        }
    }

    /**
     * 提取图片元数据（宽高等信息）
     */
    private Map<String, Object> extractImageMetadata(MultipartFile file) {
        Map<String, Object> metadata = new HashMap<>(2);
        try {
            BufferedImage image = ImageIO.read(file.getInputStream());
            if (image != null) {
                metadata.put("width", image.getWidth());
                metadata.put("height", image.getHeight());
            }
        } catch (Exception e) {
            log.warn("提取图片元数据失败: {}", e.getMessage());
        }
        return metadata;
    }

    @Override
    public PageVO<PictureVO> getPictures(PictureQueryDTO pictureQueryDTO, Long currentUserId) {
        Page<Picture> page = new Page<>(pictureQueryDTO.getCurrent(), pictureQueryDTO.getSize());

        // 构建查询条件
        LambdaQueryWrapper<Picture> queryWrapper = buildPictureQueryWrapper(pictureQueryDTO, currentUserId);

        // 执行分页查询
        Page<Picture> picturePage = this.page(page, queryWrapper);

        // 批量关联用户信息
        List<PictureVO> pictureVOList = enrichPicturesWithUserInfo(picturePage.getRecords());

        return PageVO.of(picturePage, pictureVOList);
    }

    /**
     * 构建图片查询条件
     */
    private LambdaQueryWrapper<Picture> buildPictureQueryWrapper(PictureQueryDTO queryDTO, Long currentUserId) {
        LambdaQueryWrapper<Picture> wrapper = new LambdaQueryWrapper<>();

        // 审核状态
        buildReviewStatusCondition(wrapper, queryDTO, currentUserId);

        // 空间条件
        buildSpaceCondition(wrapper, queryDTO, currentUserId);

        // 分类条件
        if (StrUtil.isNotBlank(queryDTO.getCategory())) {
            wrapper.eq(Picture::getCategory, queryDTO.getCategory());
        }

        // 标签精确匹配
        if (StrUtil.isNotBlank(queryDTO.getTag())) {
            wrapper.apply("JSON_CONTAINS(tags, JSON_QUOTE({0}))", queryDTO.getTag());
        }

        // 搜索关键词模糊匹配
        if (StrUtil.isNotBlank(queryDTO.getSearchText())) {
            wrapper.and(w -> w
                    .like(Picture::getPictureName, queryDTO.getSearchText())
                    .or()
                    .like(Picture::getIntroduction, queryDTO.getSearchText())
                    .or()
                    .like(Picture::getTags, queryDTO.getSearchText())
            );
        }

        // 用户条件
        if (queryDTO.getUserId() != null) {
            wrapper.eq(Picture::getUserId, queryDTO.getUserId());
        }

        // 排序
        buildSortCondition(wrapper, queryDTO.getSortBy());

        return wrapper;
    }

    /**
     * 构建审核状态查询条件
     */
    private void buildReviewStatusCondition(LambdaQueryWrapper<Picture> wrapper,
                                            PictureQueryDTO queryDTO, Long currentUserId) {
        if (queryDTO.getReviewStatus() != null && isAdmin(currentUserId)) {
            wrapper.eq(Picture::getReviewStatus, queryDTO.getReviewStatus());
        } else {
            wrapper.eq(Picture::getReviewStatus, ReviewStatusEnum.APPROVED.getValue());
        }
    }

    /**
     * 构建空间查询条件
     */
    private void buildSpaceCondition(LambdaQueryWrapper<Picture> wrapper,
                                     PictureQueryDTO queryDTO, Long currentUserId) {
        if (queryDTO.getSpaceId() != null) {
            if (currentUserId == null) {
                throw new BusinessException(ResultCode.USER_NOT_LOGIN);
            }
            validateSpacePermission(currentUserId, queryDTO.getSpaceId(), ACTION_VIEW);
            wrapper.eq(Picture::getSpaceId, queryDTO.getSpaceId());
        } else {
            wrapper.isNull(Picture::getSpaceId);
        }
    }

    /**
     * 构建排序条件
     */
    private void buildSortCondition(LambdaQueryWrapper<Picture> wrapper, String sortBy) {
        if (SORT_BY_POPULAR.equals(sortBy)) {
            wrapper.orderByDesc(Picture::getViewCount).orderByDesc(Picture::getCreateTime);
        } else if (SORT_BY_DOWNLOAD.equals(sortBy)) {
            wrapper.orderByDesc(Picture::getDownloadCount).orderByDesc(Picture::getCreateTime);
        } else {
            wrapper.orderByDesc(Picture::getCreateTime);
        }
    }

    /**
     * 批量关联用户信息
     */
    private List<PictureVO> enrichPicturesWithUserInfo(List<Picture> pictures) {
        // 批量获取用户信息
        Set<Long> userIds = pictures.stream()
                .map(Picture::getUserId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        Map<Long, User> userMap = new HashMap<>(userIds.size());
        if (!userIds.isEmpty()) {
            List<User> users = userService.listByIds(userIds);
            userMap = users.stream()
                    .collect(Collectors.toMap(User::getId, user -> user));
        }

        // 转换为VO并关联用户
        Map<Long, User> finalUserMap = userMap;
        return pictures.stream()
                .map(picture -> {
                    PictureVO pictureVO = PictureVO.from(picture);
                    User user = finalUserMap.get(picture.getUserId());
                    if (user != null) {
                        pictureVO.setUser(UserVO.from(user));
                    }
                    return pictureVO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public PictureVO getPictureById(Long id, Long currentUserId) {
        Picture picture = this.getById(id);
        if (picture == null) {
            throw new BusinessException(ResultCode.PICTURE_NOT_FOUND);
        }

        // 验证访问权限
        validatePictureAccess(picture, currentUserId, ACTION_VIEW);

        // 增加浏览次数
        this.incrementViewCount(id);

        // 构建返回结果
        // PictureVO.from() 方法已经自动处理了tags字段的解析
        PictureVO pictureVO = PictureVO.from(picture);

        // 关联用户信息
        User user = userMapper.selectById(picture.getUserId());
        if (user != null) {
            pictureVO.setUser(UserVO.from(user));
        }

        return pictureVO;
    }

    @Override
    @OperationLog("更新图片信息")
    @Transactional(rollbackFor = Exception.class)
    public PictureVO updatePicture(Long id, Long userId, PictureUpdateDTO pictureUpdateDTO) {
        Picture picture = this.getById(id);
        if (picture == null) {
            throw new BusinessException(ResultCode.PICTURE_NOT_FOUND);
        }

        // 验证编辑权限
        validatePictureAccess(picture, userId, ACTION_EDIT);

        // 验证目标空间权限
        Long originalSpaceId = picture.getSpaceId();
        Long targetSpaceId = pictureUpdateDTO.getSpaceId();

        if (!Objects.equals(targetSpaceId, originalSpaceId) && targetSpaceId != null) {
            validateSpacePermission(userId, targetSpaceId, ACTION_UPLOAD);
        }

        // 更新图片信息
        if (StrUtil.isNotBlank(pictureUpdateDTO.getPictureName())) {
            picture.setPictureName(pictureUpdateDTO.getPictureName());
        }
        if (pictureUpdateDTO.getIntroduction() != null) {
            picture.setIntroduction(pictureUpdateDTO.getIntroduction());
        }
        if (StrUtil.isNotBlank(pictureUpdateDTO.getCategory())) {
            picture.setCategory(pictureUpdateDTO.getCategory());
        }
        if (pictureUpdateDTO.getTags() != null) {
            picture.setTags(JSONUtil.toJsonStr(pictureUpdateDTO.getTags()));
        }
        // 始终更新spaceId字段（包括设置为null的情况）
        picture.setSpaceId(targetSpaceId);

        // TODO: 未来需要实现完整的内容审核流程（当前所有操作直接通过审核，简化流程）
        // 当前简化处理：保持原有审核状态或设置为已通过
        if (picture.getReviewStatus() == null || ReviewStatusEnum.PENDING.getValue().equals(picture.getReviewStatus())) {
            picture.setReviewStatus(ReviewStatusEnum.APPROVED.getValue());
        }

        // 保存更新
        boolean updated = this.updateById(picture);
        if (!updated) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR);
        }

        // 构建返回结果
        PictureVO pictureVO = PictureVO.from(picture);
        User user = userMapper.selectById(picture.getUserId());
        if (user != null) {
            pictureVO.setUser(UserVO.from(user));
        }

        return pictureVO;
    }

    @Override
    @OperationLog("删除图片")
    @Transactional(rollbackFor = Exception.class)
    public void deletePicture(Long id, Long userId) {
        Picture picture = this.getById(id);
        if (picture == null) {
            throw new BusinessException(ResultCode.PICTURE_NOT_FOUND);
        }

        // 验证删除权限
        validatePictureAccess(picture, userId, ACTION_DELETE);

        // 逻辑删除图片
        boolean deleted = this.removeById(id);
        if (!deleted) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR);
        }

        // TODO: 使用消息队列异步删除文件
        //       - 发送到消息队列（RabbitMQ/Kafka）
        //       - 延迟24小时删除（支持误删恢复）
        //       - 自动重试机制
        // 异步删除存储文件
        try {
            storageService.deleteFile(picture.getFileUrl());
        } catch (Exception e) {
            log.error("存储文件删除失败: {}, 错误: {}", picture.getFileUrl(), e.getMessage());
            // 不影响主流程，记录日志即可
        }
    }

    @Override
    public void downloadPicture(Long id, Long currentUserId, HttpServletResponse response) {
        // TODO: 增强下载功能
        //       - IP频率限制
        //       - 流量统计和限制
        Picture picture = this.getById(id);
        if (picture == null) {
            throw new BusinessException(ResultCode.PICTURE_NOT_FOUND);
        }

        // 验证访问权限
        validatePictureAccess(picture, currentUserId, ACTION_DOWNLOAD);

        // 增加下载次数
        this.incrementDownloadCount(id);

        // 生成下载链接（使用存储服务）
        String downloadFileName = picture.getPictureName() + "." + picture.getPicFormat();
        storageService.generateDownloadUrl(picture.getFileUrl(), downloadFileName, response);
    }

    @Override
    @OperationLog(value = "审核图片", bizType = "内容审核")
    @Transactional(rollbackFor = Exception.class)
    public void reviewPicture(Long id, Long reviewerId, PictureReview pictureReview) {
        Picture picture = this.getById(id);
        if (picture == null) {
            throw new BusinessException(ResultCode.PICTURE_NOT_FOUND);
        }

        // 验证审核状态
        if (!isValidReviewStatus(pictureReview.getReviewStatus())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR);
        }

        // 检查是否已经审核过
        if (ReviewStatusEnum.APPROVED.getValue().equals(picture.getReviewStatus()) ||
                ReviewStatusEnum.REJECTED.getValue().equals(picture.getReviewStatus())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR);
        }

        // 更新审核信息
        picture.setReviewStatus(pictureReview.getReviewStatus());
        picture.setReviewMessage(pictureReview.getReviewMessage());
        picture.setReviewerId(reviewerId);
        picture.setReviewTime(LocalDateTime.now());

        // 保存更新
        boolean updated = this.updateById(picture);
        if (!updated) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR);
        }
    }

    @Override
    @OperationLog("分享图片")
    public void sharePicture(Long id, Long currentUserId) {
        Picture picture = this.getById(id);
        if (picture == null) {
            throw new BusinessException(ResultCode.PICTURE_NOT_FOUND);
        }

        // 验证访问权限
        validatePictureAccess(picture, currentUserId, ACTION_VIEW);

        // 增加分享次数
        this.incrementShareCount(id);
    }

    /**
     * 验证空间容量限制
     */
    private void validateSpaceCapacity(Long spaceId, Long fileSize) {
        Space space = spaceMapper.selectById(spaceId);
        if (space == null) {
            throw new BusinessException(ResultCode.SPACE_NOT_FOUND);
        }

        // 查询当前空间使用情况
        LambdaQueryWrapper<Picture> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Picture::getSpaceId, spaceId);
        List<Picture> pictures = this.list(wrapper);

        // 检查图片数量限制（-1表示无限制）
        if (space.getMaxPictureCount() != -1) {
            int currentCount = pictures.size();
            if (currentCount >= space.getMaxPictureCount()) {
                throw new BusinessException(ResultCode.SPACE_FULL,
                        String.format("空间图片数量已达上限 (%d/%d)", currentCount, space.getMaxPictureCount()));
            }
        }

        // 检查存储空间限制（-1表示无限制）
        if (space.getMaxStorageSize() != -1) {
            long currentSize = pictures.stream()
                    .mapToLong(Picture::getFileSize)
                    .sum();
            if (currentSize + fileSize > space.getMaxStorageSize()) {
                long maxSizeMb = space.getMaxStorageSize() / MB_TO_BYTES;
                long currentSizeMb = currentSize / MB_TO_BYTES;
                throw new BusinessException(ResultCode.SPACE_FULL,
                        String.format("空间存储已不足，当前使用 %dMB/%dMB", currentSizeMb, maxSizeMb));
            }
        }
    }

    /**
     * 验证空间权限
     */
    private void validateSpacePermission(Long userId, Long spaceId, String action) {
        Space space = spaceMapper.selectById(spaceId);
        if (space == null) {
            throw new BusinessException(ResultCode.SPACE_NOT_FOUND);
        }

        // 查询用户在空间中的角色
        LambdaQueryWrapper<SpaceUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SpaceUser::getSpaceId, spaceId)
                .eq(SpaceUser::getUserId, userId);
        SpaceUser spaceUser = spaceUserMapper.selectOne(wrapper);

        if (spaceUser == null) {
            throw new BusinessException(ResultCode.USER_NO_PERMISSION, "无权限访问此空间");
        }

        String userRole = spaceUser.getUserRole();

        // 根据操作类型检查权限
        switch (action) {
            case ACTION_VIEW -> {
                // 所有成员都可以查看
            }
            case ACTION_UPLOAD, ACTION_EDIT -> {
                // Editor和Owner可以上传和编辑
                if (!SpaceUserRoleEnum.EDITOR.getValue().equals(userRole) &&
                        !SpaceUserRoleEnum.OWNER.getValue().equals(userRole)) {
                    throw new BusinessException(ResultCode.USER_NO_PERMISSION);
                }
            }
            case ACTION_DELETE -> {
                // 只有Owner可以删除
                if (!SpaceUserRoleEnum.OWNER.getValue().equals(userRole)) {
                    throw new BusinessException(ResultCode.USER_NO_PERMISSION);
                }
            }
            default -> throw new BusinessException(ResultCode.PARAMS_ERROR);
        }
    }

    /**
     * 验证图片访问权限
     */
    private void validatePictureAccess(Picture picture, Long currentUserId, String action) {
        // 公共空间的图片，所有人都可以查看和下载
        if (picture.getSpaceId() == null) {
            if (ACTION_VIEW.equals(action) || ACTION_DOWNLOAD.equals(action)) {
                return;
            }
            // 编辑和删除需要是图片所有者或管理员
            if (ACTION_EDIT.equals(action) || ACTION_DELETE.equals(action)) {
                if (currentUserId == null) {
                    throw new BusinessException(ResultCode.USER_NOT_LOGIN);
                }
                if (!picture.getUserId().equals(currentUserId) && !isAdmin(currentUserId)) {
                    throw new BusinessException(ResultCode.USER_NO_PERMISSION);
                }
            }
            return;
        }

        // 私有空间的图片，需要验证空间权限
        if (currentUserId == null) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN, "访问私有空间需要登录");
        }

        // 对于编辑和删除操作，图片上传者本人可以操作自己的图片（即使在空间中只是viewer角色）
        boolean isOwnerAction = ACTION_EDIT.equals(action) || ACTION_DELETE.equals(action);
        boolean isPictureOwner = picture.getUserId().equals(currentUserId);
        if (isOwnerAction && isPictureOwner) {
            return;
        }

        validateSpacePermission(currentUserId, picture.getSpaceId(), action);
    }

    /**
     * 判断是否为管理员
     */
    private boolean isAdmin(Long userId) {
        if (userId == null) {
            return false;
        }
        User user = userMapper.selectById(userId);
        return user != null && UserRoleEnum.ADMIN.getValue().equals(user.getUserRole());
    }

    /**
     * 增加浏览次数
     */
    private void incrementViewCount(Long pictureId) {
        try {
            pictureMapper.incrementViewCount(pictureId);
        } catch (Exception e) {
            log.warn("增加浏览次数失败: pictureId={}, 错误: {}", pictureId, e.getMessage());
        }
    }

    /**
     * 增加下载次数
     */
    private void incrementDownloadCount(Long pictureId) {
        try {
            pictureMapper.incrementDownloadCount(pictureId);
        } catch (Exception e) {
            log.warn("增加下载次数失败: pictureId={}, 错误: {}", pictureId, e.getMessage());
        }
    }

    /**
     * 增加分享次数
     */
    private void incrementShareCount(Long pictureId) {
        try {
            pictureMapper.incrementShareCount(pictureId);
        } catch (Exception e) {
            log.warn("增加分享次数失败: pictureId={}, 错误: {}", pictureId, e.getMessage());
        }
    }

    /**
     * 验证审核状态
     */
    private boolean isValidReviewStatus(Integer reviewStatus) {
        return (ReviewStatusEnum.PENDING.getValue().equals(reviewStatus) ||
                ReviewStatusEnum.APPROVED.getValue().equals(reviewStatus) ||
                ReviewStatusEnum.REJECTED.getValue().equals(reviewStatus));
    }

    /**
     * 从URL提取文件路径（简化版）
     *
     * @param fileUrl 文件完整URL
     * @return 文件相对路径
     */
    private String extractFilePath(String fileUrl) {
        if (StrUtil.isBlank(fileUrl)) {
            return null;
        }

        // 从URL最后一个域名分隔符后提取路径
        int lastSlashIndex = fileUrl.lastIndexOf('/');
        int domainEndIndex = fileUrl.indexOf('/', HTTPS_PROTOCOL_PREFIX_LENGTH);

        if (domainEndIndex > 0 && lastSlashIndex > domainEndIndex) {
            return fileUrl.substring(domainEndIndex + 1);
        }

        return null;
    }
}